//
//  UIView+ZHExtension.m
//  kunlun
//
//  Created by zhusanbao on 2020/10/5.
//  Copyright © 2020 zhusanbao. All rights reserved.
//

#import "UIView+ZHExtension.h"
#import "NSObject+ZHExtention.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation UIView (ZHAction)
//  针对iOS16闪退修改
+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL origSEL = @selector(hitTest:withEvent:);
        SEL newSEL = @selector(kl_hitTest:withEvent:);
        Method orig = class_getInstanceMethod(self.class, origSEL);
        Method new = class_getInstanceMethod(self.class, @selector(kl_hitTest:withEvent:));
        if(class_addMethod(self.class, origSEL, method_getImplementation(new), method_getTypeEncoding(new))){
            class_replaceMethod(self.class, newSEL, method_getImplementation(orig), method_getTypeEncoding(orig));
        }else {
            method_exchangeImplementations(orig, new);
        }
    });
}

- (void)setGestureDelegate:(id)gestureDelegate {
    objc_setAssociatedObject(self, _cmd, gestureDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)gestureDelegate {
    return objc_getAssociatedObject(self, @selector(setGestureDelegate:));
}

- (void)setZh_action:(NSDictionary *)zh_action{
    objc_setAssociatedObject(self, _cmd, zh_action, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    if (zh_action && zh_action.count > 0) {
        self.userInteractionEnabled = YES;
        if ([self isKindOfClass:[UIButton class]]) {
            UIButton *btn = (UIButton*)self;
            NSArray *actions = [btn actionsForTarget:self forControlEvent:UIControlEventTouchUpInside];
            if (![actions containsObject:@"kl_action"]) {
                [btn addTarget:self action:@selector(_runAction:) forControlEvents:UIControlEventTouchUpInside];
            }
        }else {
            for (UIGestureRecognizer *gesture in self.gestureRecognizers) {
                if ([gesture.zh_identify isEqualToString:@"kl_action"]) return;
            }
            UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_runAction:)];
            tap.zh_identify = @"kl_action";
//            tap.cancelsTouchesInView = NO;
            if (self.gestureDelegate) {
                tap.delegate = self.gestureDelegate;
            }
            [self addGestureRecognizer:tap];
        }
    }else {
        if ([self isKindOfClass:[UIButton class]]) {
            UIButton *btn = (UIButton*)self;
            NSArray *actions = [btn actionsForTarget:self forControlEvent:UIControlEventTouchUpInside];
            if ([actions containsObject:@"kl_action"]) {
                [btn removeTarget:self action:@selector(_runAction:) forControlEvents:UIControlEventTouchUpInside];
            }
        }else {
            for (UIGestureRecognizer *gesture in self.gestureRecognizers) {
                if ([gesture.zh_identify isEqualToString:@"kl_action"]) {
                    [self removeGestureRecognizer:gesture];
                    return;
                }
            }
        }
    }
}

- (NSDictionary *)zh_action{
    return objc_getAssociatedObject(self, @selector(setZh_action:));
}

- (void)setZh_enlarge:(UIEdgeInsets)zh_enlarge{
    if (UIEdgeInsetsEqualToEdgeInsets(zh_enlarge, UIEdgeInsetsZero)) {
        objc_setAssociatedObject(self, _cmd, nil, OBJC_ASSOCIATION_ASSIGN);
    }else{
        objc_setAssociatedObject(self, _cmd, [NSValue valueWithUIEdgeInsets:zh_enlarge], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
}
- (NSValue *)kl_enlargeValue{
    NSValue *vl = objc_getAssociatedObject(self, @selector(setZh_enlarge:));
    return vl;
}
- (UIEdgeInsets)zh_enlarge{
    NSValue *vl = objc_getAssociatedObject(self, @selector(setZh_enlarge:));
    return vl ? [vl UIEdgeInsetsValue] : UIEdgeInsetsZero;
}
- (UIView *)kl_hitTest:(CGPoint)point withEvent:(UIEvent*)event {
    do {
        NSValue *vl = [self kl_enlargeValue];
        if (!vl || self.isHidden || self.alpha <= 0.01 || !self.userInteractionEnabled) break;
        if (UIEdgeInsetsEqualToEdgeInsets([vl UIEdgeInsetsValue], UIEdgeInsetsZero)) break;
        CGRect rect = [self enlargedRect];
        if (CGRectEqualToRect(rect, self.bounds)) break;
        UIView *tv = [self kl_hitTest:point withEvent:event];
        if (CGRectContainsPoint(rect, point)) {
            return tv ?: self;
        }else{
            if (CGRectContainsPoint(self.bounds, point)) {
                return [self kl_hitTest:point withEvent:event];
            }else{
                UIView *ret = tv != self ? tv : nil;
                return ret ? [ret hitTest:point withEvent:event] : nil;
            }
        }
    } while (0);
    return [self kl_hitTest:point withEvent:event];
}

- (CGRect)enlargedRect {
    NSValue *vl = [self kl_enlargeValue];
    UIEdgeInsets insets = vl ? [vl UIEdgeInsetsValue] : UIEdgeInsetsZero;
    if (vl && !UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero)) {
        return CGRectMake(self.bounds.origin.x - insets.left,
                          self.bounds.origin.y - insets.top,
                          self.bounds.size.width + insets.left + insets.right,
                          self.bounds.size.height + insets.top + insets.bottom);
    } else {
        return self.bounds;
    }
}

- (void)_runAction:(UITapGestureRecognizer *)tap{
    if ([tap isKindOfClass:UIGestureRecognizer.class]) {    
        CGRect rect = [self enlargedRect];
        if (!CGRectContainsPoint(rect, [tap locationInView:self])) {return;}
    }
    tap.enabled = NO;//禁止频繁点击
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        tap.enabled = YES;
    });
    NSDictionary *action = self.zh_action;
    if (![self customRunAction:action]) {
        [self _runForwardAction:action];
    }
}
- (UIViewController *)_myViewController {
    for (UIView *view = self; view; view = view.superview) {
        UIResponder *nextResponder = [view nextResponder];
        if ([nextResponder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)nextResponder;
        }
    }
    return nil;
}
- (void)_runForwardAction:(NSDictionary *)action{
    UIViewController *vc = [self _myViewController];
    if (!vc) vc = [self currentTopViewController];
//    if (vc) {
        NSString *msg = action[@"msg"];
        if (msg) {
            SEL  sel = NSSelectorFromString(msg);//优先处理msg消息
            id   target = action[@"target"];
            if (target) {
                NSAssert([target respondsToSelector:sel], @"%@未实现 %@方法",target,msg);
                ((void(*)(id,SEL,id))objc_msgSend)(target, sel, action[@"info"]);
            }else{
                BOOL sr = [self respondsToSelector:sel];
                BOOL vr = [vc respondsToSelector:sel];
                NSAssert((sr || vr), @"%@ OR %@未实现 %@方法",self,vc,msg);
                if (vr) {
                    ((void(*)(id,SEL,id))objc_msgSend)(vc, sel, action[@"info"]);
                }else if(sr){
                    ((void(*)(id,SEL,id))objc_msgSend)(self, sel, action[@"info"]);
                }
            }
        }else{
            SEL ctls = NSSelectorFromString(@"handleCommand:");  //优先处理msg消息
            NSAssert([vc respondsToSelector:ctls], @"%@未实现 %@方法",vc, @"handleCommand:");
            ((void(*)(id,SEL,id))objc_msgSend)(vc, ctls, action);
        }
//    }else{
//        NSLog(@"ERROR : 获取viewController失败");
//    }
}

- (BOOL)customRunAction:(NSDictionary *)action{
    return NO;
}

- (void)runZHAction:(NSDictionary *)action{
    if (action) [self _runForwardAction:action];
}

- (UIViewController *)currentTopViewController{
    UIViewController* viewController = [UIApplication sharedApplication].delegate.window.rootViewController;
    return [self findBestViewController:viewController];
}

- (UIViewController *)findBestViewController:(UIViewController *)vc{
    if (vc.presentedViewController) {
        return [self findBestViewController:vc.presentedViewController];
    }else if([vc isKindOfClass:[UISplitViewController class]]){
        UISplitViewController* svc = (UISplitViewController*) vc;
        if (svc.viewControllers.count > 0){
            return [self findBestViewController:svc.viewControllers.lastObject];
        }else{
            return vc;
        }
    }else if ([vc isKindOfClass:[UINavigationController class]]) {
        UINavigationController* svc = (UINavigationController*)vc;
        if (svc.viewControllers.count > 0){
            return [self findBestViewController:svc.topViewController];
        }else{
            return vc;
        }
    }else if ([vc isKindOfClass:[UITabBarController class]]) {
        UITabBarController* svc = (UITabBarController*) vc;
        if (svc.viewControllers.count > 0){
            return [self findBestViewController:svc.selectedViewController];
        }else{
            return vc;
        }
    }else{
        return vc;
    }
}

@end

@implementation UIView (ZHExtension)

@end
